home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / util / gnu / GNU_OLEO_1_2_2.lha / oleo-1.2.2 / utils.c < prev    next >
C/C++ Source or Header  |  1993-03-03  |  20KB  |  1,139 lines

  1. /*    Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <stdio.h>
  20. #include <errno.h>
  21. #include "sysdef.h"
  22.  
  23.  
  24. /* unistd.h defines _POSIX_VERSION on POSIX.1 systems.  */
  25. #if defined(DIRENT) || defined(_POSIX_VERSION)
  26. #include <dirent.h>
  27. #define NLENGTH(dirent) (strlen((dirent)->d_name))
  28. #else /* not (DIRENT or _POSIX_VERSION) */
  29. #define dirent direct
  30. #define NLENGTH(dirent) ((dirent)->d_namlen)
  31. #ifdef SYSNDIR
  32. #include <sys/ndir.h>
  33. #endif /* SYSNDIR */
  34. #ifdef SYSDIR
  35. #include <sys/dir.h>
  36. #endif /* SYSDIR */
  37. #ifdef NDIR
  38. #include <ndir.h>
  39. #endif /* NDIR */
  40. #endif /* not (DIRENT or _POSIX_VERSION) */
  41.  
  42. #ifdef AMIGA
  43. #include <sys/dir.h>
  44. #include <sys/file.h>
  45. #endif
  46.  
  47. #ifdef __STDC__
  48. #define CONST const
  49. #undef NULL
  50. #else
  51. #define CONST
  52. #endif
  53.  
  54. #include <ctype.h>
  55. #include "utils.h"
  56.  
  57. #ifndef F_OK
  58. #define F_OK 0
  59. #endif
  60. #ifndef _IOSTRG
  61. #define _IOSTRG 0
  62. #endif
  63.  
  64. #ifdef __STDC__
  65. extern void abort (void);
  66. extern void *malloc (size_t);
  67. extern void *calloc (size_t, size_t);
  68. extern void *realloc (void *, size_t);
  69. char *strdup (CONST char *);
  70. #else
  71. extern void abort ();
  72. extern void *malloc ();
  73. extern void *calloc ();
  74. extern void *realloc ();
  75. char *strdup ();
  76. #endif
  77.  
  78. extern int sys_nerr;
  79. extern char *sys_errlist[];
  80.  
  81. struct id
  82.   {
  83.     int flag;
  84.     FILE *fp;
  85.     char *name;
  86.   };
  87.  
  88. struct id *__id_s;
  89. int __id_n;
  90. int __id_f;
  91.  
  92. int __make_backups;
  93. int __backup_by_copying;
  94.  
  95. /* Stash argv[0] here so panic will know what the program is called */
  96. char *argv_name = 0;
  97.  
  98. /* Blow chunks! */
  99. #ifdef __STDC__
  100. void
  101. panic (const char *s,...)
  102. #else
  103. void
  104. panic (s, va_alist)
  105.      char *s;
  106.      va_dcl
  107. #endif
  108. {
  109.   va_list iggy;
  110.  
  111.   var_start (iggy, s);
  112.   if (argv_name)
  113.     fprintf (stderr, "%s:", argv_name);
  114.   vfprintf (stderr, s, iggy);
  115.   putc ('\n', stderr);
  116.   va_end (iggy);
  117.   exit (2);
  118. }
  119.  
  120. /* Given a file name, come up with a backup file name. . . */
  121. char *
  122. backup_file_name (file_name)
  123.      char *file_name;
  124. {
  125.   char *dir_name, *dir_end;
  126.  
  127.   DIR *dir;
  128.   register struct dirent *dp;
  129.   int len;
  130.   int max_fnum;
  131.   int cur_fnum;
  132.  
  133.   char *tmp_ptr;
  134.  
  135.   char *return_value;
  136.  
  137.   dir_end = (char *)rindex (file_name, '/');
  138.   if (dir_end)
  139.     {
  140.       dir_name = file_name;
  141.       file_name = dir_end + 1;
  142.       *dir_end = '\0';
  143.     }
  144.   else
  145.     {
  146.       dir_name = ".";
  147.     }
  148.   len = strlen (file_name);
  149.  
  150.   dir = opendir (dir_name);
  151.   if (dir == 0)
  152.     {
  153.       if (dir_end)
  154.     *dir_end = '/';
  155.       return (char *) 0;
  156.     }
  157.  
  158.   max_fnum = 0;
  159.   while (dp = readdir (dir))
  160.     {
  161.       if (!dp->d_ino
  162.       || NLENGTH (dp) <= len
  163.       || strncmp (dp->d_name, file_name, len)
  164.       || dp->d_name[len] != '.'
  165.       || dp->d_name[len + 1] != '~'
  166.       || dp->d_name[NLENGTH(dp) - 1] != '~')
  167.     continue;
  168.  
  169.       tmp_ptr = &(dp->d_name[len + 2]);
  170.       for (cur_fnum = 0; isdigit (*tmp_ptr); tmp_ptr++)
  171.     cur_fnum = cur_fnum * 10 + *tmp_ptr - '0';
  172.       if (tmp_ptr != &(dp->d_name[NLENGTH(dp) - 1]) || cur_fnum < max_fnum)
  173.     continue;
  174.       max_fnum = cur_fnum;
  175.     }
  176.   closedir (dir);
  177.   max_fnum++;
  178.   return_value = (char *) malloc (strlen (dir_name) + len + 12);
  179.   if (!return_value)
  180.     return (char *) 0;
  181.   sprintf (return_value, "%s/%s.~%d~", dir_name, file_name, max_fnum);
  182.   if (dir_end)
  183.     *dir_end = '/';
  184.   return return_value;
  185. }
  186.  
  187.  
  188. char *
  189. __fp_name (fp)
  190.      FILE *fp;
  191. {
  192.   int n;
  193.  
  194.   for (n = 0; n < __id_n; n++)
  195.     {
  196.       if (__id_s[n].fp == fp)
  197.     return __id_s[n].name;
  198.     }
  199.   return "{Unknown file pointer}";
  200. }
  201.  
  202. void
  203. __set_fp (fp, name, flag)
  204.      FILE *fp;
  205.      CONST char *name;
  206.      int flag;
  207. {
  208.   if (__id_s == 0)
  209.     {
  210.       __id_s = ck_malloc (20 * sizeof (struct id));
  211.       __id_n = 0;
  212.       __id_f = 20;
  213.     }
  214.   else
  215.     {
  216.       int n;
  217.  
  218.       for (n = 0; n < __id_n; n++)
  219.     if (__id_s[n].fp == fp)
  220.       {
  221.         free (__id_s[n].name);
  222.         __id_s[n] = __id_s[--__id_n];
  223.         __id_f++;
  224.         break;
  225.       }
  226.     }
  227.   if (__id_f == 0)
  228.     {
  229.       __id_f = 20;
  230.       __id_s = ck_realloc (__id_s, (__id_f + __id_n) * sizeof (struct id));
  231.     }
  232.   __id_s[__id_n].flag = flag;
  233.   __id_s[__id_n].name = strdup (name);
  234.   __id_s[__id_n].fp = fp;
  235.   __id_n++;
  236.   __id_f--;
  237. }
  238.  
  239. /* Open a file or a pipe */
  240. FILE *
  241. xopen (name, mode)
  242.      CONST char *name;
  243.      CONST char *mode;
  244. {
  245.   int flag = 0;
  246.   FILE *ret;
  247.  
  248.   while (*name == ' ')
  249.     name++;
  250.   if (*name == '!')
  251.     {
  252.       name++;
  253.       ret = popen (name, mode);
  254.       flag = 1;
  255.     }
  256.   else
  257.     ret = fopen (name, mode);
  258.   if (ret == 0)
  259.     return ret;
  260.   __set_fp (ret, name, flag);
  261.   return ret;
  262. }
  263.  
  264. /* Open a file, creating a backup file if needed. . . */
  265. FILE *
  266. fopen_with_backup (name, mode)
  267.      char *name;
  268.      CONST char *mode;
  269. {
  270.   char *newname;
  271.  
  272.   if (__make_backups && *mode == 'w' && access (name, F_OK) == 0)
  273.     {
  274.       newname = backup_file_name (name);
  275.       if (!newname)
  276.     return (FILE *) 0;
  277.       if (__backup_by_copying)
  278.     {
  279.       FILE *c_in, *c_out;
  280.       int n_read;
  281. #ifdef __TURBOC__
  282.       char buf[512];
  283. #else
  284.       char buf[4096];
  285. #endif
  286.       c_in = fopen (name, "r");
  287.       c_out = fopen (newname, "w");
  288.       if (!c_in || !c_out)
  289.         return (FILE *) 0;
  290.       while ((n_read = fread (buf, 1, sizeof (buf), c_in)) > 0)
  291.         if (fwrite (buf, 1, n_read, c_out) != n_read)
  292.           return (FILE *) 0;
  293.       if (fclose (c_in) == EOF || fclose (c_out) == EOF)
  294.         return (FILE *) 0;
  295.     }
  296.       else
  297. #if defined(HAVE_RENAME)
  298.       if (rename (name, newname) < 0)
  299. #else
  300.       if (link (name, newname) || unlink (name))
  301. #endif
  302.     return (FILE *) 0;
  303.       free (newname);
  304.     }
  305.   return fopen (name, mode);
  306. }
  307.  
  308. /* Open a file or a pipe, creating a backup file if it's a file */
  309. FILE *
  310. xopen_with_backup (name, mode)
  311.      CONST char *name;
  312.      CONST char *mode;
  313. {
  314.   int flag;
  315.   FILE *ret;
  316.  
  317.   while (*name == ' ')
  318.     name++;
  319.   if (*name == '|')
  320.     {
  321.       ret = popen (name + 1, mode);
  322.       flag = 1;
  323.     }
  324.   else
  325.     {
  326.       ret = fopen_with_backup (name, mode);
  327.       flag = 0;
  328.     }
  329.   if (ret == 0)
  330.     return ret;
  331.   __set_fp (ret, name, flag);
  332.   return ret;
  333. }
  334.  
  335. /* Close something opened with xopen. . . */
  336. int
  337. xclose (fp)
  338.      FILE *fp;
  339. {
  340.   int ret;
  341.   int n;
  342.  
  343.   for (n = 0; n < __id_n; n++)
  344.     {
  345.       if (__id_s[n].fp == fp)
  346.     break;
  347.     }
  348.   if (n == __id_n)
  349.     panic ("Unknown file pointer %p given to xclose", fp);
  350.   if (__id_s[n].flag)
  351.     ret = pclose (fp);
  352.   else
  353.     ret = fclose (fp);
  354.   return ret;
  355. }
  356.  
  357. /* Fclose or panic */
  358. void
  359. ck_fclose (stream)
  360.      FILE *stream;
  361. {
  362.   if (fclose (stream) == EOF)
  363.     panic ("Couldn't close %s", __fp_name (stream));
  364. }
  365.  
  366. /* fopen or panic */
  367. void *
  368. ck_malloc (size)
  369.      size_t size;
  370. {
  371.   void *ret;
  372.  
  373.   ret = malloc (size);
  374.   if (ret == (void *) 0)
  375.     panic ("Couldn't allocate %u bytes", size);
  376.   return ret;
  377. }
  378.  
  379. char *
  380. ck_savestr (str)
  381.      char *str;
  382. {
  383.   char *newstr = 0;
  384.   if (str)
  385.     {
  386.       int len = strlen (str) + 1;
  387.       newstr = (char *) ck_malloc (len);
  388.       bcopy (str, newstr, len);
  389.     }
  390.   return newstr;
  391. }
  392.  
  393. void *
  394. ck_calloc (size)
  395.      size_t size;
  396. {
  397.   void *ret;
  398.  
  399.   ret = calloc (size, 1);
  400.   if (ret == (void *) 0)
  401.     panic ("Couldn't allocate %u bytes", size);
  402.   return ret;
  403. }
  404.  
  405. /* Realloc or panic */
  406. void *
  407. ck_realloc (ptr, size)
  408.      void *ptr;
  409.      size_t size;
  410. {
  411.   void *ret;
  412.  
  413.   if (!ptr)
  414.     ret = malloc (size);
  415.   else
  416.     ret = realloc (ptr, size);
  417.   if (ret == (void *) 0)
  418.     panic ("Couldn't re-allocate %u bytes from %p", size, ptr);
  419.   return ret;
  420. }
  421.  
  422. /* Do a sprintf into an allocated buffer. */
  423. char *
  424. #ifdef __STDC__
  425. mk_sprintf (char *str,...)
  426. {
  427.   va_list iggy;
  428. #ifdef __TURBOC__
  429.   static
  430. #endif
  431.   char tmpbuf[1024 * 8];
  432.   char *ret;
  433.  
  434.   va_start (iggy, str);
  435.   vsprintf (tmpbuf, str, iggy);
  436.   va_end (iggy);
  437.   ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
  438.   strcpy (ret, tmpbuf);
  439.   return ret;
  440. }
  441.  
  442. #else
  443.  
  444. mk_sprintf (str, va_alist)
  445.      char *str;
  446.      va_dcl
  447. {
  448.   va_list iggy;
  449. #ifdef __TURBOC__
  450.   static
  451. #endif
  452.   char tmpbuf[1024 * 8];
  453.   char *ret;
  454.  
  455.   va_start (iggy);
  456.   vsprintf (tmpbuf, str, iggy);
  457.   va_end (iggy);
  458.  
  459.   ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
  460.   strcpy (ret, tmpbuf);
  461.   return ret;
  462. }
  463.  
  464. #endif
  465.  
  466. /* Implement a variable sized LIFO stack of pointers to void */
  467.  
  468. struct stack
  469.   {
  470.     int allocated;
  471.     int used;
  472.     void **buf;
  473.   };
  474.  
  475. #define MIN_STACK 20
  476.  
  477. void *
  478. init_stack ()
  479. {
  480.   struct stack *b;
  481.  
  482.   b = (struct stack *) ck_malloc (sizeof (struct stack));
  483.   b->allocated = MIN_STACK;
  484.   b->used = 0;
  485.   b->buf = (void **) ck_malloc (MIN_STACK * sizeof (void *));
  486.   return (void *) b;
  487. }
  488.  
  489. void
  490. flush_stack (bb)
  491.      void *bb;
  492. {
  493.   struct stack *b;
  494.  
  495.   b = (struct stack *) bb;
  496.   free (b->buf);
  497.   b->buf = 0;
  498.   b->allocated = 0;
  499.   b->used = 0;
  500.   free (b);
  501. }
  502.  
  503. void
  504. push_stack (bb, add)
  505.      void *bb;
  506.      void *add;
  507. {
  508.   struct stack *b;
  509.  
  510.   b = (struct stack *) bb;
  511.   if (b->allocated == b->used)
  512.     {
  513.       b->allocated *= 2;
  514.       b->buf = (void **) ck_realloc (b->buf, b->allocated * sizeof (void *));
  515.     }
  516.   b->buf[(b->used)++] = add;
  517. }
  518.  
  519. void *
  520. pop_stack (bb)
  521.      void *bb;
  522. {
  523.   struct stack *b;
  524.  
  525.   b = (struct stack *) bb;
  526.   if (b->used == 0)
  527.     return (void *) 0;
  528.   return b->buf[--(b->used)];
  529. }
  530.  
  531. int
  532. size_stack (bb)
  533.      void *bb;
  534. {
  535.   struct stack *b;
  536.  
  537.   b = (struct stack *) bb;
  538.   return b->used;
  539. }
  540.  
  541. #ifndef HAVE_STRDUP
  542. char *
  543. strdup (str)
  544.      CONST char *str;
  545. {
  546.   char *ret;
  547.  
  548.   ret = (char *) ck_malloc (strlen (str) + 2);
  549.   strcpy (ret, str);
  550.   return ret;
  551. }
  552. #endif
  553.  
  554. #ifndef HAVE_STRICMP
  555. /*
  556.  * stricmp - compare string s1 to s2, ignoring case
  557.  */
  558.  
  559. #ifdef __STDC__
  560. int
  561. stricmp (const char * s1, const char * s2)
  562. #else
  563. int
  564. stricmp (s1, s2)
  565.      CONST char *s1;
  566.      CONST char *s2;
  567. #endif
  568. {
  569.   register CONST char *scan1;
  570.   register CONST char *scan2;
  571.   register char chr1, chr2;
  572.  
  573.   scan1 = s1;
  574.   scan2 = s2;
  575.   do
  576.     {
  577.       chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
  578.       chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
  579.       scan1++;
  580.       scan2++;
  581.     }
  582.   while (chr1 && chr1 == chr2);
  583.  
  584.   /*
  585.      * The following case analysis is necessary so that characters
  586.      * which look negative collate low against normal characters but
  587.      * high against the end-of-string NUL.
  588.      */
  589.   if (chr1 == '\0' && chr2 == '\0')
  590.     return 0;
  591.   else if (chr1 == '\0')
  592.     return -1;
  593.   else if (chr2 == '\0')
  594.     return 1;
  595.   else
  596.     return chr1 - chr2;
  597. }
  598. #endif
  599.  
  600. #ifndef HAVE_STRINCMP
  601. /* strincmp - compare first N chars of strings S1 and S2 */
  602. #ifdef __STDC__
  603. int
  604. strincmp (const char * s1, const char * s2, size_t n)
  605. #else
  606. int
  607. strincmp (s1, s2, n)
  608.      CONST char *s1;
  609.      CONST char *s2;
  610.      size_t n;
  611. #endif
  612. {
  613.   register CONST char *scan1;
  614.   register CONST char *scan2;
  615.   register size_t count;
  616.   register char chr1, chr2;
  617.  
  618.   scan1 = s1;
  619.   scan2 = s2;
  620.   count = n;
  621.   do
  622.     {
  623.       chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
  624.       chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
  625.       scan1++;
  626.       scan2++;
  627.     }
  628.   while (--count != 0 && chr1 && chr1 == chr2);
  629.  
  630.   /* if (count == (size_t)-1)
  631.         return 0; */
  632.  
  633.   /*
  634.      * The following case analysis is necessary so that characters
  635.      * which look negative collate low against normal characters but
  636.      * high against the end-of-string NUL.
  637.      */
  638.   if (chr1 == '\0' && chr2 == '\0')
  639.     return 0;
  640.   else if (chr1 == '\0')
  641.     return -1;
  642.   else if (chr2 == '\0')
  643.     return 1;
  644.   else
  645.     return chr1 - chr2;
  646. }
  647. #endif
  648.  
  649. #ifndef HAVE_STRSTR
  650. CONST char *
  651. strstr (s, wanted)
  652.      CONST char *s;
  653.      CONST char *wanted;
  654. {
  655.   register CONST char *scan;
  656.   register size_t len;
  657.   register char firstc;
  658.  
  659.   /*
  660.      * The odd placement of the two tests is so "" is findable.
  661.      * Also, we inline the first char for speed.
  662.      * The ++ on scan has been moved down for optimization.
  663.      */
  664.   firstc = *wanted;
  665.   len = strlen (wanted);
  666.   for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;)
  667.     if (*scan++ == '\0')
  668.       return (char *) 0;
  669.   return scan;
  670. }
  671. #endif
  672.  
  673. #ifdef __STDC__
  674. char *
  675. err_msg (void)
  676. #else
  677. char *
  678. err_msg ()
  679. #endif
  680. {
  681.   int n;
  682.   static char buf[80];
  683.  
  684.   n = errno;
  685.  
  686.   if (n < sys_nerr)
  687.     return sys_errlist[n];
  688.   sprintf (buf, "Unknown error code %d (%#x)", n, n);
  689.   return buf;
  690. }
  691.  
  692.  
  693. /* Take a quoted string and return the character it represents */
  694. #ifdef __STDC__
  695. int
  696. string_to_char (char ** ptr)
  697. #else
  698. int
  699. string_to_char (ptr)
  700.      char **ptr;
  701. #endif
  702. {
  703.   char *str;
  704.   int i;
  705.   char c1, c2;
  706.  
  707.   str = *ptr;
  708.   if (str[0] == '\\')
  709.     {
  710.       switch (str[1])
  711.     {
  712.     case '\\':
  713.       i = '\\';
  714.       break;
  715.     case 'b':
  716.       i = '\b';
  717.       break;
  718.     case 'f':
  719.       i = '\f';
  720.       break;
  721.     case 'n':
  722.       i = '\n';
  723.       break;
  724.     case 'r':
  725.       i = '\r';
  726.       break;
  727.     case 't':
  728.       i = '\t';
  729.       break;
  730.     case 'x':
  731.       c1 = str[2];
  732.       c2 = str[3];
  733.       if (isxdigit (c1))
  734.         {
  735.           if (isdigit (c1))
  736.         c1 -= '0';
  737. /*
  738.           else if (isupper (c1))
  739.         c1 -= 'A';
  740.           else
  741.         c1 -= 'a';
  742.           if (isxdigit (c2))
  743.         {
  744.           if (isdigit (c2))
  745.             c2 -= '0';
  746.           else if (isupper (c2))
  747.             c2 -= 'A';
  748.           else
  749.             c2 -= 'a';
  750.           i = c1 * 0x10 + c2;
  751.           str++;
  752.         }
  753.           else
  754.         i = c1;
  755. */
  756.           else if (isupper (c1))
  757.         c1 = c1 - 'A' + 10;
  758.           else
  759.         c1 = c1 - 'a' + 10;
  760.           if (isxdigit (c2))
  761.         {
  762.           if (isdigit (c2))
  763.             c2 -= '0';
  764.           else if (isupper (c2))
  765.             c2 = c2 - 'A'+ 10;
  766.           else
  767.             c2 = c2 - 'a' + 10;
  768.           i = c1 * 0x10 + c2;
  769.           str++;
  770.         }
  771.           else
  772.         i = c1;
  773.         }
  774.       else
  775.         i = 'x';
  776.       break;
  777.  
  778.     case '0':
  779.     case '1':
  780.     case '2':
  781.     case '3':
  782.     case '4':
  783.     case '5':
  784.     case '6':
  785.     case '7':
  786.       if (str[2] >= '0' && str[2] <= '7')
  787.         {
  788.           if (str[3] >= '0' && str[3] <= '7')
  789.         {
  790.           i = (str[1] - '0') * 0100 + (str[2] - '0') * 010 + (str[3] - '0');
  791.           str += 2;
  792.         }
  793.           else
  794.         {
  795.           i = (str[1] - '0') * 010 + (str[2] - '0');
  796.           str++;
  797.         }
  798.         }
  799.       else
  800.         i = str[1] - '0';
  801.       break;
  802.     default:
  803.       i = str[0];
  804.       --str;
  805.       break;
  806.     }
  807.       str += 2;
  808.       *ptr = str;
  809.       return i;
  810.     }
  811.  
  812.   if (str[0] == 'M' && str[1] == '-')
  813.     {
  814.       i = 0x80;
  815.       str += 2;
  816.     }
  817.   else
  818.     i = 0;
  819.  
  820.   if (str[0] == '^')
  821.     {
  822.       if (str[1] == '?')
  823.     i += 0x7f;
  824.       else if (str[1] >= '@' && str[1] <= '_')
  825.     i |= str[1] - '@';
  826.       else if (str[1] >= 'a' && str[1] <= 'z')
  827.     i = str[1] - 'a' + 1;
  828.       else if (str[1] == '\0' || isspace (str[1]))
  829.     i = '^';
  830.       else
  831.     return -1;
  832.       str += 2;
  833.     }
  834.   else
  835.     {
  836.       i |= str[0];
  837.       str++;
  838.     }
  839.   *ptr = str;
  840.   return i;
  841. }
  842.  
  843. /* Take a char and turn it into a readable string */
  844. #ifdef __STDC__
  845. char *
  846. char_to_string (int ch)
  847. #else
  848. char *
  849. char_to_string (ch)
  850.      int ch;
  851. #endif
  852. {
  853.   static char buf[5] = "M-";
  854.  
  855.   if (ch >= ' ' && ch <= '~')
  856.     {
  857.       buf[3] = ch;
  858.       return &buf[3];
  859.     }
  860.   if (ch & 0x80)
  861.     {
  862.       ch &= 0x7f;
  863.       if (ch == 0x7f || ch < ' ')
  864.     {
  865.       buf[2] = '^';
  866.       buf[3] = (ch == 0x7f ? '?' : ch + '@');
  867.     }
  868.       else
  869.     {
  870.       buf[2] = ch;
  871.       buf[3] = '\0';
  872.     }
  873.       return &buf[0];
  874.     }
  875.   if (ch == 0x7f || ch < ' ')
  876.     {
  877.       buf[2] = '^';
  878.       buf[3] = (ch == 0x7f ? '?' : ch + '@');
  879.       return &buf[2];
  880.     }
  881.   return "huh";
  882. }
  883.  
  884.  
  885. #ifdef __STDC__
  886. long
  887. astol (char **ptr)
  888. #else
  889. long
  890. astol (ptr)
  891.      char **ptr;
  892. #endif
  893. {
  894.   register long i = 0;
  895.   register int c;
  896.   int sign = 1;
  897.   char *s;
  898.  
  899.   s = *ptr;
  900.   /* Skip whitespace */
  901.   while (isspace (*s))
  902.     if (*s++ == '\0')
  903.       {
  904.     *ptr = s;
  905.     return (0);
  906.       }
  907.   /* Check for - or + */
  908.   if (*s == '-')
  909.     {
  910.       s++;
  911.       sign = -1;
  912.     }
  913.   else if (*s == '+')
  914.     s++;
  915.  
  916.   /* Read in the digits */
  917.   for (; c = *s; s++)
  918.     {
  919.       if (!isdigit (c) || i > 214748364 || (i == 214748364 && c > (sign > 0 ? '7' : '8')))
  920.     break;
  921.       i = i * 10 + c - '0';
  922.     }
  923.   *ptr = s;
  924.   return i * sign;
  925. }
  926.  
  927. /*
  928.  *    astof - accept a number of the form:
  929.  *        (and ignores leading white space)
  930.  *
  931.  *    null    ::=
  932.  *    digit    ::= 0|1|2|3|4|5|6|7|8|9
  933.  *    digits    ::= <digit>*
  934.  *    DIGITS    ::= <digit>+
  935.  *    sign    ::= <null> | + | -
  936.  *    -------------------------------
  937.  *        accepted:
  938.  *    -------------------------------
  939.  *    integer    ::= <sign><DIGITS>
  940.  *    real    ::= <integer> . <digits> | <null> . <DIGITS>
  941.  *    epart    ::= e <integer> | E <integer>
  942.  *    float    ::= <integer> <epart> | <real> <epart>
  943.  *
  944.  *    Always returned as a double
  945.  *
  946.  *    There is no particular attempt to reduce mpys/divs
  947.  *    those machines that are still out there (eg. PDP11/Small)
  948.  *    that shun floating point arithmetic might rethink this routine.
  949.  */
  950.  
  951. static double exps0[10] =
  952. {1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9};
  953. static double exps1[10] =
  954. {1E00, 1E10, 1E20, 1E30
  955. #ifndef vax
  956.  ,1E40, 1E50, 1E60, 1E70, 1E80, 1E90
  957. #endif
  958. };
  959.  
  960. #define REGISTER register
  961.  
  962. #ifdef __STDC__
  963. double
  964. astof (char **sp)
  965. #else
  966. double
  967. astof (sp)
  968.      char **sp;
  969. #endif
  970. {
  971.   REGISTER char *s;
  972.   REGISTER char *cp;
  973.   long ipart, epart;
  974.   int neg = 0;
  975.   double res;
  976.   int n;
  977.  
  978.   s = *sp;
  979.   while (isspace (*s))
  980.     {
  981.       s++;
  982.       if (*s == '\0')
  983.     {
  984.       *sp = s;
  985.       return (0.0);
  986.     }
  987.     }
  988.   /*
  989.      *    Need to handle sign here due to '-.3' or '-0.3'
  990.      */
  991.   if (*s == '-')
  992.     {
  993.       ++neg;
  994.       ++s;
  995.     }
  996.   else if (*s == '+')
  997.     ++s;
  998.   cp = s;
  999.   /*
  1000.      *    get ipart handling '.n' case
  1001.      */
  1002.   res = 0.0;
  1003.   while (isdigit (*s))
  1004.     {
  1005.       for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
  1006.     ipart = ipart * 10 + *s++ - '0';
  1007.       res = res * exps0[n] + (double) ipart;
  1008.     }
  1009.   if (s == cp)
  1010.     {
  1011.       if (*s == '.')
  1012.     ipart = 0;
  1013.       else
  1014.     {
  1015.       *sp = s;
  1016.       return (0.0);
  1017.     }
  1018.     }
  1019.   /*
  1020.      *    either we find a '.' or e|E or done
  1021.      */
  1022.   if (*s == '.')
  1023.     {
  1024.       int m;
  1025.       ++s;
  1026.  
  1027.       m = 0;
  1028.       while (isdigit (*s))
  1029.     {
  1030.       for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
  1031.         ipart = ipart * 10 + *s++ - '0';
  1032.       m += n;
  1033.       if (m >= 100)
  1034.         continue;
  1035.       if (m >= 10)
  1036.         res += ((double) ipart) / (exps1[m / 10] * exps0[m % 10]);
  1037.       else
  1038.         res += ((double) ipart) / exps0[m];
  1039.     }
  1040.     }
  1041.   /*
  1042.      *    In either case (.) handle E part
  1043.      */
  1044.   if (*s == 'e' || *s == 'E')
  1045.     {
  1046.       int eneg;
  1047.  
  1048.       ++s;
  1049.       epart = 0;
  1050.       eneg = 0;
  1051.       if (*s == '-')
  1052.     {
  1053.       eneg++;
  1054.       s++;
  1055.     }
  1056.       else if (*s == '+')
  1057.     s++;
  1058.       while (isdigit (*s))
  1059.     epart = epart * 10 + *s++ - '0';
  1060.       if (eneg)
  1061.     {
  1062. #ifndef vax
  1063.       while (epart >= 100)
  1064.         {
  1065.           res /= 1E100;
  1066.           epart -= 100;
  1067.         }
  1068. #endif
  1069.       if (epart > 9)
  1070.         {
  1071.           res /= exps1[epart / 10];
  1072.           epart %= 10;
  1073.         }
  1074.       if (epart)
  1075.         res /= exps0[epart];
  1076.     }
  1077.       else
  1078.     {
  1079. #ifndef vax
  1080.       while (epart >= 100)
  1081.         {
  1082.           res *= 1E100;
  1083.           epart -= 100;
  1084.         }
  1085. #endif
  1086.       if (epart > 9)
  1087.         {
  1088.           res *= exps1[epart / 10];
  1089.           epart %= 10;
  1090.         }
  1091.       if (epart)
  1092.         res *= exps0[epart];
  1093.     }
  1094.     }
  1095.   /*
  1096.      *    fix sign
  1097.      */
  1098.   if (neg)
  1099.     res = -res;
  1100.   *sp = s;
  1101.   return (res);
  1102. }
  1103.  
  1104. #ifdef TEST_ASTOF
  1105. main ()
  1106. {
  1107.   char buf[80];
  1108.   char *ptr;
  1109.   double at, ast;
  1110.   double atof ();
  1111.  
  1112.   while (gets (buf))
  1113.     {
  1114.       at = atof (buf);
  1115.       ptr = buf;
  1116.       ast = astof (&ptr);
  1117.       printf ("%15.6f %15.6f %s ", at, ast, at == ast ? "eq" : "NEQ");
  1118.       if (*ptr)
  1119.     printf ("%s->'%s'\n", buf, ptr);
  1120.       else
  1121.     printf ("%s\n", buf);
  1122.     }
  1123. }
  1124. char *
  1125. ck_savestr (str)
  1126.      char *str;
  1127. {
  1128.   char *newstr = 0;
  1129.   if (str)
  1130.     {
  1131.       int len = strlen (str) + 1;
  1132.       newstr = (char *) ck_malloc (len);
  1133.       bcopy (str, newstr, len);
  1134.     }
  1135.   return newstr;
  1136. }
  1137.  
  1138. #endif
  1139.